package com.j.lemon.learn.basic.aspects;

import com.j.lemon.learn.basic.annotations.Limiter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * @Author lijunjun
 * @Date 2018-12-26 10:42
 * @Description
 */
@Component
@Aspect
public class RateLimiterAspect {
    @Resource
    private RedisTemplate<String,Long> redisTemplate;

    private static final Logger logger = LoggerFactory.getLogger(RateLimiterAspect.class);

    @Pointcut(value = "@annotation(limiter)",argNames = "limiter")
    public void limit(Limiter limiter){}

    @Before(value = "RateLimiterAspect.limit(limiter)", argNames = "joinPoint,limiter")
    public void before(JoinPoint joinPoint ,Limiter limiter){
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature)signature;
        Method target = methodSignature.getMethod();
        int limit = limiter.limit();
        int sec = limiter.sec();
//        Integer momentLimit = redisTemplate.opsForValue().get(target.getName());
//        if(momentLimit==null){
//            redisTemplate.opsForValue().set(target.getName(),1,sec, TimeUnit.SECONDS);
//        }else if (momentLimit<limit){
//            redisTemplate.opsForValue().set(target.getName(),momentLimit+1,sec,TimeUnit.SECONDS);
//        }else{
//            System.out.println("服务器繁忙");
//        }
//        System.out.println(momentLimit);
        logger.info("before--target:{},limit:{},sec:{}",target.getName(),limit,sec);

    }

    @AfterReturning(value = "limit(limiter)",argNames = "joinPoint,limiter")
    public void afterReturning(JoinPoint joinPoint,Limiter limiter){
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        int limit = limiter.limit();
        int sec = limiter.sec();
        logger.info("after returning--target:{},limit:{},sec:{}",name,limit,sec);
    }

    @After(value = "limit(limiter)", argNames = "joinPoint,limiter")
    public void after(JoinPoint joinPoint,Limiter limiter){
        String name = joinPoint.getSignature().getName();
        int limit = limiter.limit();
        int sec = limiter.sec();
        logger.info("after--target:{},limit:{},sec:{}",name,limit,sec);
    }

    @AfterThrowing(value = "limit(limiter)", argNames = "joinPoint,limiter,ex",throwing = "ex")
    public String afterThrow(JoinPoint joinPoint,Limiter limiter,Throwable ex){
        String name = joinPoint.getSignature().getName();
        int limit = limiter.limit();
        int sec = limiter.sec();
        logger.info("afterThrow--target:{},limit:{},sec:{},ex:{}",name,limit,sec,ex);
        return "404";
    }

    @Around(value = "limit(limiter)", argNames = "proceedingJoinPoint,limiter")
    public String around(ProceedingJoinPoint proceedingJoinPoint,Limiter limiter) throws Throwable {
        logger.info("around-before");
        //执行目标对象方法
        proceedingJoinPoint.proceed();
        logger.info("around-after");
//        String name = joinPoint.getSignature().getName();
        int limit = limiter.limit();
        int sec = limiter.sec();
        logger.info("around--target:{},limit:{},sec:{},ex:{}","name",limit,sec);
        return "404";
    }


}
